home *** CD-ROM | disk | FTP | other *** search
-
- program DirectoryDemo;
- {
- Demonstration of how to search a PC-DOS/MS-DOS file directory for
- a file specification, which can contain global characters ('*' and '?'),
- using DOS function calls hex 4E and hex 4F. Displays a list of names
- and sizes of files which match the specification.
-
- Program compiles correctly under versions 2 and 3 of Turbo Pascal.
- Tested under IBM PC-DOS ver 2.10 and 3.0, and Compaq MS-DOS 2.11.
-
- Copyright June 1985 by D.F. Yriart.
-
- Sub-directory attribute test modified 28 July 1985.
- }
-
- type
- UserSpec = string[64];
- Registers = record
- AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags : Integer;
- end;
- FileName = string[13];
- DTAPointer = ^DTARecord;
- DTARecord = record { Layout of DTA on return from calls }
- DOSReserved : array[1..21] of byte;
- Attribute : byte;
- FileTime, { packed in special format }
- FileDate, { " " " " }
- SizeLow,
- SizeHigh : integer;
- FoundName : array[1..13] of char;
- end;
-
- const
- NUL = ^@; { character 0, used to terminate ASCIIZ string }
- SeekAttrib = $10; { search for files & sub-directories }
-
- var
- TransferRec : DTAPointer; { will point to program DTA }
- MatchPtrn : UserSpec; { in Turbo Pascal string format }
- RetName : FileName; { name found by call }
- FilSize : Real; { size of file found }
- Count : Integer;
- NoFind, LastFile,
- SubDirec : Boolean;
-
- procedure PointDTA(Var DTARec : DTAPointer);
- {
- Use function hex 2F to locate the starting address of the Data
- Transfer Area (DTA) and point to it.
-
- Pointer will be used by file match procedures to find the data
- returned in the DTA.
- }
-
- Const GetDTA = $2F00; { function number }
-
- var
- Regs : Registers;
-
- Begin
- Regs.AX := GetDTA; { load function number }
- MsDos(Regs); { make call to DOS }
-
- { On return from call to GetDTA, ES register contains DTA segment
- address, BX register contains DTA offset in segment }
-
- DTARec := Ptr(Regs.ES,Regs.BX); { Set pointer }
- End;
-
- function SizeOfFile(HiWord, LoWord : Integer) : Real;
- {
- Converts the file size returned by DOS in two 16 bit words (unsigned
- integers) into a real number.
- }
-
- Var
- BigNo, Size : Real;
-
- Begin
- BigNo := (MaxInt * 2.0) + 2;
- if HiWord < 0 then Size := (BigNo + HiWord) * BigNo
- else Size := HiWord * BigNo;
- if LoWord >= 0 then Size := Size + LoWord
- else Size := Size + (BigNo + LoWord);
- SizeOfFile := Size
- End;
-
- procedure FindFirst(Pattern : UserSpec; Var Found : FileName; Var Size : Real;
- Var NoMatch : Boolean; Var LastOne : Boolean;
- Var SubDir : Boolean);
- {
- Function hex 4E returns first file name that matches user's specification.
-
- If an error occurs, the carry flag will be set and DOS will return error
- code 2 or 18 in the AX register. The procedure sets NoMatch and LastOne
- depending on the error code.
-
- The filespec to search for must be stored as an ASCIIZ string, terminated
- by a byte of binary zeros (character NUL). When the call is made, the
- DS and DX registers point to the ASCIIZ string.
-
- The file attribute to search for can be loaded in the CX register.
-
- If a match occurs, the DTA will be loaded with information about
- the file which was found. This procedure recovers the file name and
- attribute of the found file. SubDir returns true if the file's
- attribute is "subdirectory".
- }
-
- Const FindFirst = $4E00; { function number }
-
- Type
- ASCIIZ = array[1..64] of char;
-
- var
- FileSpec : ASCIIZ; { search pattern in DOS ASCIIZ string format }
- Regs : Registers;
- PosInStr,
- Count : Integer;
- FoundLen : Byte absolute Found;
-
- Begin
- { Convert the file name to an ASCIIZ string for the function call. }
- for PosInStr := 1 to length(Pattern) do
- FileSpec[PosInStr] := Pattern[PosInStr];
- FileSpec[length(Pattern) + 1] := NUL;
-
- With Regs do
- begin
- DS := Seg(FileSpec); { Point to ASCIIZ string }
- DX := Ofs(FileSpec);
- CX := SeekAttrib; { File attribute to look for }
- AX := FindFirst; { load function number }
- MsDos(Regs);
- if (Flags and 1) > 0 then { test carry flag }
- begin { Handle error return codes }
- Case AX of
- 2 : begin { No match }
- NoMatch := True;
- LastOne := True;
- end;
- 18 : begin { No more files }
- NoMatch := False;
- LastOne := True;
- end;
- else
- writeln(^G'Can''t interpret error return code');
- Halt;
- end; { Case }
- end
- else
- begin { No error return code }
- NoMatch := False;
- LastOne := False;
- end;
- end; { with Regs }
-
- { Capture returned file name and attribute, other information
- such as file size, time and date is also returned in the DTA.
- TransferRec points to the record superimposed on the DTA. }
-
- if (not NoMatch) then
- with TransferRec^ do
- begin
- Found := FoundName;
-
- { Find number of characters returned in the file name area }
- Count := 0;
- While Found[Count] <> NUL do Count := Count + 1;
- FoundLen := Count; { set the length of the name string }
-
- { Blank out any garbage characters passed from the DTA }
- For Count := length(Found) + 1 to 13 do Found := Found + ' ';
-
- { Test whether the file is a subdirectory and set flag. }
- if (Attribute and SeekAttrib) > 0 then SubDir := True
- else SubDir := False;
-
- { Get the file size if file is not a subdirectory. }
- if not SubDir then Size := SizeOfFile(SizeHigh,SizeLow)
- else Size := 0.0;
-
- end; { with TransferRec }
- End;
-
- procedure FindNext(Var Found : FileName; Var Size : Real;
- Var LastOne : Boolean; Var SubDir : Boolean);
- {
- Function hex 4F returns next matching file name. When error 18 is
- returned there are no more matches. The search criteria set up by
- function hex 4E are used by this call, and information is returned
- in the DTA as described for procedure FindFirst.
- }
-
- Const FindNext = $4F00; { function number }
-
- var
- Regs : Registers;
- Count : Integer;
- FoundLen : Byte absolute Found;
-
- Begin
- With Regs do
- begin
- AX := FindNext;
- MsDos(Regs);
- if (Flags and 1) > 0 then { Handle error return codes }
- if AX = 18 then LastOne := True { No more files }
- else
- begin
- writeln(^G'Can''t interpret error return code');
- Halt;
- end
- else LastOne := False; { No error return code }
- end; { with Regs }
-
- { Capture returned file name and attribute }
- with TransferRec^ do
- begin
- Found := FoundName;
-
- { Set length of file name and clear "garbage." }
- Count := 0;
- While Found[Count] <> NUL do Count := Count + 1;
- FoundLen := Count;
- For Count := length(Found) + 1 to 13 do Found := Found + ' ';
-
- { Test for subdirectory. }
- if (Attribute and SeekAttrib) > 0 then SubDir := True
- else SubDir := False;
-
- { Get the file size if file is not a subdirectory. }
- if not SubDir then
- Size := SizeOfFile(SizeHigh,SizeLow)
- else Size := 0.0;
-
- end; { with TransferRec }
- End;
-
- {
- **********************************
- * MAIN PROGRAM *
- **********************************
- }
-
- BEGIN
- ClrScr;
- writeln(' -- Demonstration of Directory Search Calls --');
- write(' Find? ');
- readln(MatchPtrn); { The user's search specification }
- writeln;
- Count := 0;
-
- PointDTA(TransferRec); { Set the DTA pointer }
-
- { Call function hex 4E to search for first match. }
- FindFirst(MatchPtrn,RetName,FilSize,NoFind,LastFile,SubDirec);
-
- if NoFind or LastFile then writeln('File not found.')
- else
- begin
- { Display additional matches and keep looking until no
- more are found. Display in three columns. }
-
- While (not LastFile) do
- begin
- if SubDirec then LowVideo; { Display subdirectories in }
- write(RetName,' ',FilSize:8:0,' '); { low intensity. }
- NormVideo;
- Count := Count + 1;
- if (Count mod 3) = 0 then Writeln;
- { Call function hex 4F to search for another match. }
- FindNext(RetName,FilSize,LastFile,SubDirec);
- end;
- end;
-
- { Close up the display with a count of files found. }
- if (Count mod 3) <> 0 then writeln;
- writeln;
- write('*** ',Count,' Files or ');
- LowVideo;
- write('Sub-Directories');
- NormVideo;
- writeln(' found ***');
- END.
- ** '